import mx.utils.Delegate;

import gugga.collections.HashTable;
import gugga.collections.ObjectHashTable;
import gugga.tween.AbstractTween;
import gugga.utils.DebugUtils;
import gugga.utils.OnEnterFrameBeacon;
import gugga.tween.FrameTween;
import gugga.events.EventDispatcher;
[Event("tweensUpdated")]

/**
 * @author Todor Kolev
 */
class gugga.tween.TweensManager extends EventDispatcher
{
	private var mTweens : ObjectHashTable;
	
	private static var mInstance : TweensManager;
	public static function get Instance() : TweensManager
	{
		if(!mInstance)
		{
			mInstance = new TweensManager();
		}
		
		return mInstance;
	}
	
	
	private function TweensManager() 
	{
		super();
		mTweens = new ObjectHashTable();
		OnEnterFrameBeacon.Instance.addEventListener("onEnterFrame", Delegate.create(this, onEnterFrameHandler));
	}
	
	public function doTween(aTween : AbstractTween) : Void
	{
		//TODO: Exception if already have tween by this property - Assertion!!!
		
		if(aTween.Duration > 0)
		{
			mTweens.add(aTween, aTween);
		}
		else
		{
			for (var key:String in aTween.TweeningProperties)
			{
				aTween.Subject[key] = aTween.TweeningProperties[key];
			}
			
			aTween.TweenUpdateDelegate();
			aTween.TweenFinishedDelegate();
		}
	}
	
	//TODO: aTweeningProperties can be array; should be optimized
	public function stopTweensFor(aSubject : Object, aTweeningProperties : HashTable) : Void
	{
		var tween : AbstractTween;
		for (var tweenKey:String in mTweens)
		{
			tween = AbstractTween(mTweens[tweenKey]);
			
			for (var propertyKey:String in aTweeningProperties)
			{
				if(tween.TweeningProperties.containsKey(propertyKey))
				{
					delete tween.TweeningProperties[propertyKey];
				}
			}
			
			if(tween.TweeningProperties.count <= 0)
			{
				delete mTweens[tweenKey];
			}
		}
	}
	
	public function stopTween(aTween : AbstractTween) : Void
	{
		mTweens.remove(aTween);
	}
	
	private function onEnterFrameHandler() : Void 
	{
		var tween : AbstractTween;
		for (var key:String in mTweens)
		{
			tween = AbstractTween(mTweens[key]);
			tween.update();
			
			if(tween.Finished)
			{
				delete mTweens[key];
			}
		}
		
		dispatchEvent({type: "tweensUpdated", target: this});
	}
}